#ifndef TB_BASE_ASSERT_HPP__
#define TB_BASE_ASSERT_HPP__

#include <vector>
#include <assert.h>

#include <boost/lexical_cast.hpp> //for TB_SMART_ASSERT's value capture

#include "string/utf_string_conversions.hpp"

#include "base_export.hpp"
#include "base_fwd.hpp"
#include "string.hpp"
#include "arbitrary_cast.hpp"

TB_NAMESPACE_BEGIN

typedef void (*SmartAssertHandler)(const SmartAssert &a);
TB_BASE_API void SetAssertHandle(SmartAssertHandler *handler);

MSVC_PUSH_DISABLE_WARNING(4355);

class TB_BASE_API SmartAssert {
public:
  SmartAssert& TB_SMART_ASSERT_A;

  SmartAssert& TB_SMART_ASSERT_B;
  
  SmartAssert(const std::string& expr, const char* file, int line) 
    : TB_SMART_ASSERT_A(*this), 
      TB_SMART_ASSERT_B(*this) {
    Initialize(expr, file, line);
  };

  SmartAssert(const string16& expr, const char* file, int line) 
    : TB_SMART_ASSERT_A(*this), 
      TB_SMART_ASSERT_B(*this) {
    Initialize(UTF16ToUTF8(expr), file, line);
  };

  ~SmartAssert(); 

  SmartAssert& PrintContext(const std::string& key, const std::string& val);
  const std::string& expr() const;
  const std::string& file() const;
  int line() const;
  std::vector<std::pair<std::string, std::string> > values() const;
 private:
  void Initialize(const std::string& expr, const char* file, int line);
 private:
  struct SmartAssertImpl;
  SmartAssertImpl* impl_;
};

MSVC_POP_WARNING();

TB_NAMESPACE_END

#define TB_SMART_ASSERT_A(x) TB_SMART_ASSERT_OP(x, B)
#define TB_SMART_ASSERT_B(x) TB_SMART_ASSERT_OP(x, A)
#define TB_SMART_ASSERT_OP(x, next) \
  TB_SMART_ASSERT_A.PrintContext(#x, TB_NAMESPACE::ArbitraryCast<std::string>(x)).TB_SMART_ASSERT_##next

#define TB_SMART_ASSERT(expr) \
  if ( (expr) );\
  else TB_NAMESPACE::SmartAssert(#expr, __FILE__, __LINE__).TB_SMART_ASSERT_A

#define TB_ASSERT assert

// simple static assertion
// #define TB_STATIC_ASSERT(cond, msg) \
//   { static const char msg[(cond) ? 1 : -1] = {0}; (void)msg[0]; }

#if defined(TB_DEBUG)
# define TB_CHECK TB_ASSERT
#else
# define TB_CHECK(expr) (void)(expr)
#endif

#define TB_VERIFY TB_CHECK

#endif //TB_CORE_ASSERT_HPP__
